package sse

import (
	"bufio"
	"encoding/json"
	"fmt"
	"gitee.com/jn-qq/go-tools/slices"
	"io"
	"strings"
	"time"
)

// LingXiDialogueResult 灵犀对话返回结果规整
type LingXiDialogueResult struct {
	Question       string         `json:"question"`
	Message        string         `json:"message"`
	CardList       []Card         `json:"cardList"`
	ThinkList      []string       `json:"thinkList"`
	Barcontentlist []Bar          `json:"barcontentlist"`
	Status         string         `json:"status"`
	Intent         string         `json:"intent"`
	Slot           map[string]any `json:"slot"`
	ErrMessage     string         `json:"errMessage"`
	TraceId        string         `json:"traceId"`
	SessionId      string         `json:"sessionId"`
	SpendTime      time.Duration
	UniqueId       []string
}

// ToMap 将 LingXiDialogueResult 结构体实例转换为 map 类型。
// 这个函数方便后续处理或传输数据，通过将结构体成员映射到 map，提供更灵活的数据访问方式。
func (l *LingXiDialogueResult) ToMap() map[string]any {
	// 封装通用的 marshal 函数用于减少重复代码
	// 该函数接收任意类型的数据，将其转换为 JSON 字符串。
	// 如果转换过程中发生错误，返回错误信息。
	marshal := func(v any) string {
		data, err := json.Marshal(v)
		if err != nil {
			// 可选：记录错误日志
			// log.Printf("JSON Marshal error: %v", err)
			return err.Error()
		}
		return string(data)
	}

	// 简单断言
	l.CheckThinkList()

	// 构建并返回包含 LingXiDialogueResult 结构体所有字段的 map。
	// 对于复杂类型（如切片或结构体），使用上述 marshal 函数将其转换为 JSON 字符串。
	// 对于简单的类型（如字符串或整数），直接添加到 map 中。
	// think 字段是一个切片，使用 "-->" 作为分隔符连接成单个字符串。
	result := map[string]any{
		"问题":        l.Question,
		"备注":        l.ErrMessage,
		"卡片":        marshal(l.CardList),
		"气泡":        marshal(l.Barcontentlist),
		"状态":        l.Status,
		"回复":        strings.TrimSpace(l.Message),
		"意图":        l.Intent,
		"耗时/ms":     l.SpendTime.Milliseconds(),
		"Slot":      marshal(l.Slot),
		"traceId":   l.TraceId,
		"sessionId": l.SessionId,
		"Think":     strings.Join(l.ThinkList, "\n"),
	}

	// 返回构建的 map。
	return result
}

func (l *LingXiDialogueResult) CheckThinkList() {
	// 错误信息列表
	var errInfoList = []string{l.ErrMessage}

	// 判断新版思考体是否正常
	var lastThought string
	for i, thought := range l.ThinkList {
		if !strings.Contains(thought, "action") {
			if !slices.Contains(errInfoList, "新版思考体异常") {
				errInfoList = append(errInfoList, "新版思考体异常")
			}
		}
		if i > 5 {
			if !slices.Contains(errInfoList, "新版思考体可能异常，思考步骤太多") {
				errInfoList = append(errInfoList, "新版思考体可能异常，思考步骤太多")
			}
		}
		if lastThought == thought {
			if !slices.Contains(errInfoList, "新版思考体有重复") {
				errInfoList = append(errInfoList, "新版思考体有重复")
			}
		}
		if strings.TrimSpace(thought) == "(action)" || strings.TrimSpace(thought) == "(ds)" {
			if !slices.Contains(errInfoList, "新版思考体有空白思考步骤") {
				errInfoList = append(errInfoList, "新版思考体有空白思考步骤")
			}
		}
	}

	l.ErrMessage = strings.TrimSpace(strings.Join(errInfoList, "\n"))
}

// Card 卡片结构体
type Card struct {
	Cardnumber  string `json:"cardnumber" mapstructure:"cardnumber"`
	ReturnURL   string `json:"returnURL,omitempty" mapstructure:"returnURL,omitempty"`
	CardType    int64  `json:"cardtype,omitempty" mapstructure:"cardtype,omitempty"`
	Url         string `json:"url,omitempty" mapstructure:"url,omitempty"`
	StateNumber string `json:"statenumber,omitempty" mapstructure:"statenumber,omitempty"`
	Data        *struct {
		Msg       string         `json:"msg,omitempty" mapstructure:"msg,omitempty"`
		ApiName   string         `json:"apiName,omitempty" mapstructure:"apiName,omitempty"`
		Success   bool           `json:"success,omitempty" mapstructure:"success,omitempty"`
		ApiCnName string         `json:"apiCnName,omitempty" mapstructure:"apiCnName,omitempty"`
		Content   map[string]any `json:"content,omitempty" mapstructure:"content,remain"`
	} `json:"data,omitempty" mapstructure:"data,omitempty"`
}

func (c *Card) CardId() string {
	return fmt.Sprintf("card-%s-%d-%s-%s", c.Cardnumber, c.CardType, c.ReturnURL, c.Url)
}

// Bar 气泡结构体
type Bar struct {
	BarType     any    `json:"barType,omitempty" mapstructure:"barType,omitempty"`
	BarGroupId  string `json:"barGroupId,omitempty" mapstructure:"barGroupId,omitempty"`
	Ishighlight any    `json:"ishighlight,omitempty" mapstructure:"ishighlight,omitempty"`
	ReturnText  string `json:"returnText,omitempty" mapstructure:"returnText,omitempty"`
	ReturnTxt   string `json:"returnTxt,omitempty" mapstructure:"returnTxt,omitempty"`
	Text        string `json:"text,omitempty" mapstructure:"text,omitempty"`
	Txt         string `json:"txt,omitempty" mapstructure:"txt,omitempty"`
}

func (b *Bar) BarId() string {
	return fmt.Sprintf("bar-%s-%s-%s-%s-%s", b.BarGroupId, b.BarType, b.Ishighlight, b.Text, b.Txt)
}

const (
	sseBreak = iota
	sseContinue
	ssePass
)

func readerFromSse(reader *bufio.Reader, delim byte) (string, int) {
	line, err := reader.ReadString(delim)
	if err != nil {
		if err == io.EOF {
			return "", sseBreak
		}
	}

	line = strings.TrimSpace(line)
	if !strings.HasPrefix(line, "data:") {
		return "", sseContinue
	}
	line = strings.TrimSpace(strings.TrimPrefix(line, "data:"))

	// 处理结束标记
	if strings.HasSuffix(line, "[DONE]") {
		return "", sseBreak
	}
	return line, ssePass
}
